﻿using Microsoft.Win32;
using MyPlayer.Common;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Threading;

namespace MyPlayer.Views
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        string[] _videoTypes = new string[] { ".3g2", ".3gp", ".3gp2", ".3gpp", ".amv", ".asf", ".avi", ".bik", ".bin", ".divx", ".drc", ".dv", ".f4v", ".flv", ".gvi", ".gxf", ".m1v", ".m2v", ".m2t", ".m2ts", ".m4v", ".mkv", ".mov", ".mp2", ".mp4", ".mp4v", ".mpe", ".mpeg", ".mpeg1", ".mpeg2", ".mpeg4", ".mpg", ".mpv2", ".mts", ".mxf", ".mxg", ".nsv", ".nuv", ".ogg", ".ogm", ".ogv", ".ps", ".rec", ".rm", ".rmvb", ".rpl", ".thp", ".tod", ".ts", ".tts", ".txd", ".vob", ".vro", ".webm", ".wm", ".wmv", ".wtv", ".xesc" };
        string[] _audioTypes = new string[] { ".3ga", ".669", ".a52", ".acc", ".ac3", ".adt", ".adts", ".aif", ".aiff", ".amr", ".aob", ".ape", ".awb", ".caf", ".dts", ".flac", ".it", ".kar", ".m4a", ".m4b", ".m4p", ".m5p", ".mid", ".mka", ".mlp", ".mod", ".mpa", ".mp1", ".mp2", ".mp3", ".mpc", ".mpga", ".mus", ".oga", ".ogg", ".oma", ".opus", ".qcp", ".ra", ".rmi", ".s3m", ".sid", ".spx", ".thd", ".tta", ".voc", ".vqf", ".w64", ".wav", ".wma", ".wv", ".xa", ".xm" };

        private double m_OriginalLeft;
        private double m_OriginalTop;
        private double m_OriginalWidth;
        private double m_OriginalHeight;

        private JObject config = new JObject();
        private DateTime lastTimeMouseMove = DateTime.Now;
        private DateTime lastTimeVolumeChange = DateTime.Now;
        private object lockPlayerTimeChange = new object();
        private object lockPlayerVolumeChange = new object();
        private readonly TaskScheduler _syncContextTaskScheduler = TaskScheduler.FromCurrentSynchronizationContext();

        private Vlc.DotNet.Core.VlcMediaPlayer VlcMediaPlayer
        {
            get { return vlcControl.SourceProvider.MediaPlayer; }
        }

        public MainWindow()
        {
            InitializeComponent();

            this.StateChanged += MainWindow_StateChanged;
            //this.KeyDown += MainWindow_KeyDown;
            this.PreviewKeyDown += MainWindow_PreviewKeyDown;
            this.Drop += MainWindow_Drop;
            this.MouseMove += MainWindow_MouseMove;

            InitMediaPlayer();
            InitConfig();

            PlayViedeo("");

            //UI定时器
            DispatcherTimer timer1 = new DispatcherTimer();
            timer1.Interval = new TimeSpan(0, 0, 0, 0, 100);//设置的间隔为100毫秒
            timer1.Tick += Timer1_Tick; ;
            timer1.IsEnabled = true;
            //timer1.Start();
        }

        private void MainWindow_PreviewKeyDown(object sender, KeyEventArgs e)
        {
            MainWindow_KeyDown(sender, e);
        }

        private void MainWindow_MouseMove(object sender, MouseEventArgs e)
        {
            this.lastTimeMouseMove = DateTime.Now;
            gridTop.Visibility = Visibility.Visible;
            gridBottom.Visibility = Visibility.Visible;
            Mouse.OverrideCursor = null;
            this.ResizeMode = ResizeMode.CanResizeWithGrip;
        }

        private void MainWindow_Drop(object sender, DragEventArgs e)
        {
            string fileName = ((System.Array)e.Data.GetData(DataFormats.FileDrop)).GetValue(0).ToString();
            PlayViedeo(fileName);
        }

        private void InitConfig()
        {
            if (!File.Exists("./config.json"))
            {
                config = new JObject();
                config.Add("VideoFileName", "");
                return;
            }
            var file = File.ReadAllText("./config.json");
            config = JObject.Parse(file);


            VlcMediaPlayer.Audio.Volume = Convert.ToInt32(config["Volume"]);
        }

        private void PlayViedeo(string fileName)
        {
            string path = fileName;
            if (string.IsNullOrWhiteSpace(fileName))
            {
                path = config["VideoFileName"].ToString();
                if (path == "")
                {
                    return;
                }
            }

            var url = new Uri(path);
            //if (VlcMediaPlayer.IsPlaying())
            //{
            //    VlcMediaPlayer.Stop();
            //}
            VlcMediaPlayer.Play(url);
            txtVideoTitle.Text = url.LocalPath;

            if (url.Scheme == "file")
            {
                txtVideoTitle.Text = System.IO.Path.GetFileName(path);
            }
            else
            {
                txtVideoTitle.Text = url.Segments[url.Segments.Length - 1];
            }

            if (string.IsNullOrWhiteSpace(fileName) && config.ContainsKey(path))
            {
                var time = Convert.ToInt64(config[path]);
                if (time == VlcMediaPlayer.Length)
                {
                    VlcMediaPlayer.Time = 0;
                }
                else
                {
                    VlcMediaPlayer.Time = time;
                }
            }

            SetConfig("VideoFileName", path);
        }

        private void Timer1_Tick(object? sender, EventArgs e)
        {
            try
            {
                if (VlcMediaPlayer.State == Vlc.DotNet.Core.Interops.Signatures.MediaStates.Playing
                    && DateTime.Now.Subtract(lastTimeMouseMove).TotalSeconds >= 5)
                {
                    gridTop.Visibility = Visibility.Collapsed;
                    gridBottom.Visibility = Visibility.Collapsed;
                    Mouse.OverrideCursor = Cursors.None;
                    this.ResizeMode = ResizeMode.CanResize;
                }

                if (DateTime.Now.Subtract(lastTimeVolumeChange).TotalSeconds > 3)
                {
                    lblTip.Visibility = Visibility.Collapsed;
                }

                if (VlcMediaPlayer.IsPlaying())
                {
                    SystemSleepManagement.ResetSleepTimer(true);
                }

            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine("UI定时器出错，" + ex.Message);
            }
        }

        private void MainWindow_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.Key == Key.Down)
            {
                VlcMediaPlayer.Audio.Volume -= 5;
            }
            else if (e.Key == Key.Up)
            {
                VlcMediaPlayer.Audio.Volume += 5;
            }
            else if (e.Key == Key.Left)
            {
                var t = Convert.ToInt64(txtBackwardTime.Text);
                VlcMediaPlayer.Time -= t * 1000;
                lblTip.Text = string.Format("快退：{0}秒", t);
            }
            else if (e.Key == Key.Right)
            {
                var t = Convert.ToInt64(txtForwardTime.Text);
                VlcMediaPlayer.Time += t * 1000;
                lblTip.Text = string.Format("快退：{0}秒", t);
            }
            else if (e.Key == Key.Space)
            {
                btnPlay_Click(btnPlay, new RoutedEventArgs());
            }
            else if (e.Key == Key.Escape)
            {
                if (this.WindowState == WindowState.Maximized)
                {
                    this.WindowState = WindowState.Normal;
                }
            }
        }

        private void InitMediaPlayer()
        {
            var vlcLibDirectory = new DirectoryInfo(System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "libvlc", IntPtr.Size == 4 ? "win-x86" : "win-x64"));

            var options = new string[]
        {
                //添加日志
                "--file-logging", "-vvv", "--logfile=Logs.log"
            // VLC options can be given here. Please refer to the VLC command line documentation.
        };
            //初始化播放器
            this.vlcControl.SourceProvider.CreatePlayer(vlcLibDirectory/*, options*/);

            VlcMediaPlayer.Playing += MediaPlayer_Playing;
            VlcMediaPlayer.Paused += MediaPlayer_Paused;
            VlcMediaPlayer.Stopped += MediaPlayer_Stopped;
            VlcMediaPlayer.TimeChanged += MediaPlayer_TimeChanged;
            VlcMediaPlayer.AudioVolume += MediaPlayer_AudioVolume;
        }

        long playerLastTime = 0;

        private void MediaPlayer_TimeChanged(object? sender, Vlc.DotNet.Core.VlcMediaPlayerTimeChangedEventArgs e)
        {
            lock (lockPlayerTimeChange)
            {
                //playerLastTime = e.NewTime;
                Console.WriteLine("MediaPlayer_TimeChanged:{0}", e.NewTime);

            SetConfig(config["VideoFileName"].ToString(), e.NewTime);

            var position = new TimeSpan(0, 0, 0, 0, (int)VlcMediaPlayer.Time).ToString(@"hh\:mm\:ss");//视频已播放的时间
            var length = new TimeSpan(0, 0, 0, 0, (int)(VlcMediaPlayer.Length - VlcMediaPlayer.Time)).ToString(@"hh\:mm\:ss");//视频剩余时间           

                //this.Dispatcher.BeginInvoke(delegate ()
    
                this.Dispatcher.Invoke(DispatcherPriority.Normal, (ThreadStart)delegate ()
                {
                    if (sliderVideo.Maximum != VlcMediaPlayer.Length)
                    {
                        sliderVideo.Maximum = VlcMediaPlayer.Length;
                    }
                    sliderVideo.Value = e.NewTime;

                    txtVideoTime.Text = position;
                    txtRemainingTime.Text = length;
                });

                //Task.Factory.StartNew(() =>
                //{
                //        if (sliderVideo.Maximum != VlcMediaPlayer.Length)
                //        {
                //            sliderVideo.Maximum = VlcMediaPlayer.Length;
                //        }
                //        sliderVideo.Value = e.NewTime;

                //        txtVideoTime.Text = position;
                //        txtRemainingTime.Text = length;
                //}, new CancellationTokenSource().Token, TaskCreationOptions.None, _syncContextTaskScheduler).Wait();
            }
        }

        private void MediaPlayer_AudioVolume(object? sender, Vlc.DotNet.Core.VlcMediaPlayerAudioVolumeEventArgs e)
        {
            lock (lockPlayerVolumeChange)
            {
                var value = "\ue683";

                if (VlcMediaPlayer.Audio.Volume == 0 || VlcMediaPlayer.Audio.IsMute)
                {
                    value = "\ue684";
                }
                else if (VlcMediaPlayer.Audio.Volume <= 50)
                {
                    value = "\ue67f";
                }

                this.Dispatcher.Invoke(DispatcherPriority.Normal, (ThreadStart)delegate ()
                {
                    btnVolume.Content = value;
                    txtVolume.Text = VlcMediaPlayer.Audio.Volume.ToString();
                    lblTip.Text = string.Format("音量：{0}", VlcMediaPlayer.Audio.Volume);

                    sliderVolume.Maximum = 100;
                    if (sliderVolume.Maximum >= VlcMediaPlayer.Audio.Volume)
                    {
                        sliderVolume.Value = VlcMediaPlayer.Audio.Volume;
                    }
                });

                SetConfig("Volume", VlcMediaPlayer.Audio.Volume);
            }
        }

        private void MediaPlayer_Stopped(object? sender, Vlc.DotNet.Core.VlcMediaPlayerStoppedEventArgs e)
        {
            this.Dispatcher.Invoke(DispatcherPriority.Normal, (ThreadStart)delegate ()
            {
                btnPlay.Content = "\uea82";
            });

            DeleteConfig(config["VideoFileName"].ToString());
        }

        private void MediaPlayer_Paused(object? sender, Vlc.DotNet.Core.VlcMediaPlayerPausedEventArgs e)
        {
            this.Dispatcher.Invoke(DispatcherPriority.Normal, (ThreadStart)delegate ()
            {
                btnPlay.Content = "\uea82";
            });
        }

        private void MediaPlayer_Playing(object? sender, Vlc.DotNet.Core.VlcMediaPlayerPlayingEventArgs e)
        {
            this.Dispatcher.Invoke(DispatcherPriority.Normal, (ThreadStart)delegate ()
            {
                btnPlay.Content = "\uea81";
            });
        }

        private void MainWindow_StateChanged(object? sender, EventArgs e)
        {
            btnFullScreen.Content = this.WindowState == WindowState.Maximized ? "\ue81f" : "\ue820";
        }

        private void btnMin_Click(object sender, RoutedEventArgs e)
        {
            this.WindowState = WindowState.Minimized;
        }

        private void btnMax_Click(object sender, RoutedEventArgs e)
        {
            var workArea = SystemParameters.WorkArea;
            if (this.Width != workArea.Width && this.Height != workArea.Height)
            {
                this.Left = 0;
                this.Top = 0;
                this.Width = workArea.Width;
                this.Height = workArea.Height;
            }
            else
            {
                this.Left = this.m_OriginalLeft;
                this.Top = this.m_OriginalTop;
                this.Width = this.m_OriginalWidth;
                this.Height = this.m_OriginalHeight;
            }
        }

        private void btnClose_Click(object sender, RoutedEventArgs e)
        {
            this.Close();
        }

        private void Window_MouseDown(object sender, MouseButtonEventArgs e)
        {
            if (e.ClickCount == 2 && e.ChangedButton == MouseButton.Left)
            {
                this.btnMax_Click(btnMax, e);
            }
            else if (e.ButtonState == MouseButtonState.Pressed && e.ChangedButton == MouseButton.Left)
            {
                this.DragMove();
            }
        }

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            this.m_OriginalLeft = this.Left;
            this.m_OriginalTop = this.Top;
            this.m_OriginalWidth = this.Width;
            this.m_OriginalHeight = this.Height;
            this.Title = "电影测试";
        }

        private void btnFullScreen_Click(object sender, RoutedEventArgs e)
        {
            this.WindowState = this.WindowState != WindowState.Maximized ? WindowState.Maximized : this.WindowState = WindowState.Normal;
        }

        private void btnPlay_Click(object sender, RoutedEventArgs e)
        {
            if (VlcMediaPlayer.State == Vlc.DotNet.Core.Interops.Signatures.MediaStates.Paused)
            {
                VlcMediaPlayer.Play();
            }
            else if (VlcMediaPlayer.State == Vlc.DotNet.Core.Interops.Signatures.MediaStates.Playing)
            {
                VlcMediaPlayer.Pause();
            }
            else
            {
                PlayViedeo(config["VideoFileName"].ToString());
            }
        }

        private void btnBackward_Click(object sender, RoutedEventArgs e)
        {
            MainWindow_KeyDown(
                sender,
                new KeyEventArgs(
                    Keyboard.PrimaryDevice,
                    Keyboard.PrimaryDevice.ActiveSource,
                    0,
                    Key.Left
                )
            );
        }

        private void btnForward_Click(object sender, RoutedEventArgs e)
        {
            MainWindow_KeyDown(
              sender,
              new KeyEventArgs(
                  Keyboard.PrimaryDevice,
                  Keyboard.PrimaryDevice.ActiveSource,
                  0,
                  Key.Right
              )
          );
        }

        private void sliderVideo_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
        {
            var time = (long)e.NewValue;
            if (time != VlcMediaPlayer.Time)
            {
                VlcMediaPlayer.Time = time;
            }
        }

        private void sliderVolume_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
        {
            var value = (int)e.NewValue;
            if (value != VlcMediaPlayer.Audio.Volume)
            {
                VlcMediaPlayer.Audio.Volume = value;
            }
        }

        private void MWindow_MouseWheel(object sender, MouseWheelEventArgs e)
        {
            if (e.Delta < 0)
            {
                MainWindow_KeyDown(
                  sender,
                  new KeyEventArgs(
                      Keyboard.PrimaryDevice,
                      Keyboard.PrimaryDevice.ActiveSource,
                      0,
                      Key.Down
                  )
                 );
            }
            else if (e.Delta > 0)
            {
                MainWindow_KeyDown(
                  sender,
                  new KeyEventArgs(
                      Keyboard.PrimaryDevice,
                      Keyboard.PrimaryDevice.ActiveSource,
                      0,
                      Key.Up
                  )
                );
            }
        }

        private void btnVolume_MouseEnter(object sender, MouseEventArgs e)
        {
            gridVolume.Visibility = Visibility.Visible;
        }

        private void MenuItem1_Click(object sender, RoutedEventArgs e)
        {
            Microsoft.Win32.OpenFileDialog ofd = new Microsoft.Win32.OpenFileDialog();

            ofd.Filter = "视频文件|*" + string.Join(";*", this._videoTypes);
            ofd.Filter += "|音频文件|*" + string.Join(";*", this._audioTypes);
            ofd.Filter += "|所有文件|*.*";

            if (ofd.ShowDialog() == true)
            {
                this.PlayViedeo(ofd.FileName);
            }
        }

        private void SetConfig(string key, object value)
        {
            if (!config.ContainsKey(key))
            {
                config.Add(key, value.ToString());
            }
            else
            {
                config[key] = value.ToString();
            }

            using (System.IO.StreamWriter file = new System.IO.StreamWriter("./config.json"))
            {
                file.Write(config.ToString());
            }
        }

        private void DeleteConfig(string key)
        {
            if (config.ContainsKey(key))
            {
                config.Remove(key);
            }

            using (System.IO.StreamWriter file = new System.IO.StreamWriter("./config.json"))
            {
                file.Write(config.ToString());
            }
        }

        private void btnVolume_Click(object sender, RoutedEventArgs e)
        {
            VlcMediaPlayer.Audio.IsMute = VlcMediaPlayer.Audio.IsMute ? false : true;

            var value = "\ue683";
            if (VlcMediaPlayer.Audio.Volume == 0 || VlcMediaPlayer.Audio.IsMute)
            {
                value = "\ue684";
            }
            else if (VlcMediaPlayer.Audio.Volume <= 50)
            {
                value = "\ue67f";
            }
            btnVolume.Content = value;
        }

        private void Grid_MouseDown(object sender, MouseButtonEventArgs e)
        {
            if (e.ClickCount == 2 && e.ChangedButton == MouseButton.Left)
            {
                this.btnMax_Click(btnMax, e);
            }
            else if (e.ButtonState == MouseButtonState.Pressed && e.ChangedButton == MouseButton.Left)
            {
                this.DragMove();
            }
        }

        private void btnVolume_MouseLeave(object sender, MouseEventArgs e)
        {
            gridVolume.Visibility = Visibility.Collapsed;
        }

        private void TextBox_TextChanged(object sender, TextChangedEventArgs e)
        {
            lblTip.Visibility = Visibility.Visible;
            lastTimeVolumeChange = DateTime.Now;
        }

        private void btnSetting_Click(object sender, RoutedEventArgs e)
        {
            new SettingWindow().ShowDialog();
        }

        private void sliderVideo_MouseMove(object sender, MouseEventArgs e)
        {
            var x = e.GetPosition(sliderVideo).X;
            var w = sliderVideo.ActualWidth;
            sliderVideo.ToolTip = new TimeSpan(0, 0, 0, 0, (int)(x / w * sliderVideo.Maximum)).ToString(@"hh\:mm\:ss");
        }
    }
}